<script>
import VStack from '@/components/Layout/Stack/VStack';

/**
 * Used to display a percentage and indicate the health based on boundaries set.
 */
export default {
  name: 'PercentageCircle',

  components: { VStack },

  props: {
    /**
     * A value representing the percentage to be displayed. *Must be a value between 0 and 1*.
     */
    value: {
      type:      Number,
      required:  true,
      validator: (value) => {
        return value >= 0 && value <= 1;
      }
    },
    /**
     * A number representing the lower bound the `value` can be before it ends up in a **warning** state. *Must be a value between 0 and 1*.
     */
    lowerWarningBound: { type: Number, default: undefined },
    /**
     * A number representing the upper bound the `value` can be before it ends up in a **warning** state. *Must be a value between 0 and 1*.
     */
    upperWarningBound: { type: Number, default: undefined },
    /**
     * A number representing the lower bound the `value` can be before it ends up in an **error** state. *Must be a value between 0 and 1*.
     */
    lowerErrorBound:   { type: Number, default: undefined },
    /**
     * A number representing the upper bound the `value` can be before it ends up in an **error** state. *Must be a value between 0 and 1*.
     */
    upperErrorBound:   { type: Number, default: undefined }
  },

  computed: {
    valueD() {
      return describeArc(50, 50, 45, 180, 180 + (360 * this.value));
    },
    printedValue() {
      return (this.value * 100)
        .toFixed(1)
        .replace(/\.0$/, '');
    },
    valueClass() {
      const errorClass = 'error';
      const warningClass = 'warning';
      const successClass = 'success';

      if (this.lowerErrorBound && this.value <= this.lowerErrorBound) {
        return errorClass;
      }

      if (this.lowerWarningBound && this.value <= this.lowerWarningBound) {
        return warningClass;
      }

      if (this.upperErrorBound && this.value >= this.upperErrorBound) {
        return errorClass;
      }

      if (this.upperWarningBound && this.value >= this.upperWarningBound) {
        return warningClass;
      }

      return successClass;
    }
  }
};

function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
  const angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;

  return {
    x: centerX + (radius * Math.cos(angleInRadians)),
    y: centerY + (radius * Math.sin(angleInRadians))
  };
}

function describeArc(x, y, radius, startAngle, endAngle) {
  const start = polarToCartesian(x, y, radius, endAngle);
  const end = polarToCartesian(x, y, radius, startAngle);

  const largeArcFlag = endAngle - startAngle <= 180 ? '0' : '1';

  const d = [
    'M', start.x, start.y,
    'A', radius, radius, 0, largeArcFlag, 0, end.x, end.y
  ].join(' ');

  return d;
}
</script>

<template>
  <VStack class="percentage-circle" horizontal-align="center">
    <svg viewBox="0 0 100 100" class="gauge">
      <circle class="dial" fill="none" cx="50" cy="50" r="45" />
      <path v-if="value < 1" class="value" :class="valueClass" fill="none" :d="valueD" />
      <circle
        v-else
        class="value"
        :class="valueClass"
        fill="none"
        cx="50"
        cy="50"
        r="45"
      />
    </svg>
    <div class="printed-value mt-10">
      <h1>{{ printedValue }}%</h1>
    </div>
  </VStack>
</template>

<style lang="scss" scoped>
    .percentage-circle {
        text-align: center;

        svg {
            $size: 150px;
            width: $size;
            height: $size;

            .dial {
                stroke: var(--muted);
                stroke-width: 5;
            }

            .value {
                stroke-width: 5.5;
                stroke-linecap: round;

                &.success {
                    stroke: var(--success);
                }

                &.warning {
                    stroke: var(--warning);
                }

                &.error {
                    stroke: var(--error);
                }
            }
        }

        .printed-value {
            text-align: center;
        }
    }
</style>
